<?php
// ------------------------------------------------------------------------
// |@Author       : Jarmin <edshop@qq.com>
// |@----------------------------------------------------------------------
// |@Date         : 2023-05-13 17:41:58
// |@----------------------------------------------------------------------
// |@LastEditTime : 2023-06-03 22:46:29
// |@----------------------------------------------------------------------
// |@LastEditors  : Jarmin <jarmin@ladmin.cn>
// |@----------------------------------------------------------------------
// |@Description  : 
// |@----------------------------------------------------------------------
// |@FilePath     : Role.php
// |@----------------------------------------------------------------------
// |@Copyright (c) 2023 http://www.ladmin.cn   All rights reserved. 
// ------------------------------------------------------------------------
namespace app\api\model;

use think\admin\Model;

class Role extends Model
{
    /**
     * 定义一个从 Role 到 Auth 模型的一对一反向关联。
     * @return \think\model\relation\HasOne    返回 Auth 模型的一对一关联
     */
    public function auth()
    {
        // 设定 Auth 模型的外键为当前 Role 模型的 role_id。
        // 注意：默认 Auth 模型的主键为 id。
        return $this->hasOne(Auth::class, 'role_id', 'id')->withDefault(['menu_id_list' => '[]']);
    }

    /**
     * 获取用户角色信息
     * @param int|null $userId 用户id
     * @param array $role_list 用户角色列表
     * @return \think\Collection|mixed
     */
    public static function getUserRole(?int $userId, array $role_list): mixed
    {
        if ($userId !== null && $userId !== 1) {
            $roles = static::mk()->whereIn('id', $role_list)->select();
        } else {
            $roles = static::mk()->select();
        }
        return self::getDashboardGrid($roles);
    }

    /**
     * 获取仪表盘栅格布局信息，方便前端渲染仪表盘页面
     * @param \think\Collection $role 角色数据
     * @return array
     */
    private static function getDashboardGrid(\think\Collection $role): array
    {
        $dashboard_grid = [];

        // 合并角色的栅格布局信息，去重后返回
        foreach ($role->column('grid_list') as $v){
            $dashboard_grid = array_unique(array_merge_recursive($dashboard_grid, json_decode($v)));
        }

        return $dashboard_grid;
    }
    
    /**
     * 获取角色列表
     * @param  array $data 查询条件列表，包含 name 和 pageSize 等字段
     * @return array       返回角色数据列表
     */
    public static function listRole(array $data): array
    {
        // 根据查询条件组织 where 子句查询数组
        $where = !empty($data['name']) ? [["name", "like", "%" . $data['name'] . "%"]] : [["id", ">", 0]];
        // 根据请求参数组织 limit 子句查询数组
        $limit = ['list_rows'=>!empty($data['pageSize']) ? $data['pageSize'] : 20, 'page'=>!empty($data['page']) ? $data['page'] : 1];
        // 查询数据库获取符合条件的角色数据
        $roles = static::mk()->where($where)->order('id', 'asc')->paginate($limit)->toArray();
        // 返回角色数据列表
        return $roles;
    }

    /**
     * 新增或更新角色
     * @param  array $data 角色数据，包括 id、name 和 description 等字段
     * @return array       返回新增/更新的角色数据
     */
    public static function saveRole(array $data): array
    {
        $fn = function () use ($data) {
            if (empty($data['id'])) {
                $data['grid_list'] = json_encode(["welcome","ver"]);
                // 如果没有id值，则插入数据
                static::mk()->strict(false)->insert($data);
            } else {
                // 如果有id值，说明是更新操作
                static::mk()->strict(false)->where('id', $data['id'])->update($data);
            }
            
            return $data;
        };

        return static::mk()->runTransaction($fn);
    }

    /**
     * 更新角色状态
     * @param  array $data 角色状态数据，包含 id 和 status 等字段
     * @return int         返回更新的状态数
     */
    public static function stateRole(array $data): int
    {
        $fn = function () use ($data) {
            // 根据 $data 中的 id 值，更新角色状态为 $data 中的 status 值。
            $status = static::mk()->where('id', $data['id'])->update(['status' => $data['status']]);
            return $status;
        };

        return static::mk()->runTransaction($fn);
    }

    /**
     * 分配角色权限
     * @param  array $data 包含 role_ids 和 menu_ids 两个字段
     * @return bool        返回是否分配成功
     */
    public static function allotRole(array $data): bool
    {
        $fn = function () use ($data) {
            // 遍历 role_ids，分别为每个角色分配权限。
            foreach ($data['role_ids'] as $role_id)
            {
                // 根据 role_id 查找对应的 Role 模型。
                $role = Role::find($role_id);

                // 为Role模型新增属性值并保存
                $role->data_type = $data['data_type'] ?? '';
                $role->dept_list = json_encode($data['dept_list']) ?? [];
                $role->grid_list = json_encode($data['grid_list']) ?? [];
                $role->dashboard = $data['dashboard'];
                $role->save();

                // 根据 role_id 查找对应的 Auth 模型。
                $auth = $role->auth;
                // 修改 Auth 模型的 role_id 和 menu_id_list 属性。
                $auth->role_id = $role_id;
                $auth->menu_id_list = json_encode($data['menu_ids']);
                $auth->save();
            }
            
            return true;
        };

        return static::mk()->runTransaction($fn);
    }

    /**
     * 删除角色及其关联的权限
     * @param  array $data 包含 ids 字段，待删除角色的 ID 列表
     * @return bool        是否删除成功
     */
    public static function removeRole(array $data): bool
    {
        $fn = function () use ($data) {
            // 遍历 ids，分别删除对应角色及其关联的权限。
            foreach ($data['ids'] as $roleId) {
                // 根据角色 ID 查找对应的 Role 模型。
                $role = static::mk()->find($roleId);
                if ($role) {
                    // 如果找到了对应角色，则删除其关联的 Auth 模型和自身。
                    $role->auth()->delete();
                    $role->delete();
                }
            }

            return true;
        };

        return static::mk()->runTransaction($fn);
    }
}